home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkPack.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  50.4 KB  |  1,769 lines

  1. /* 
  2.  * tkPack.c --
  3.  *
  4.  *    This file contains code to implement the "packer"
  5.  *    geometry manager for Tk.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkPack.c 1.63 96/02/15 18:52:33
  14.  */
  15.  
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18.  
  19. typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side;
  20.  
  21. /* For each window that the packer cares about (either because
  22.  * the window is managed by the packer or because the window
  23.  * has slaves that are managed by the packer), there is a
  24.  * structure of the following type:
  25.  */
  26.  
  27. typedef struct Packer {
  28.     Tk_Window tkwin;        /* Tk token for window.  NULL means that
  29.                  * the window has been deleted, but the
  30.                  * packet hasn't had a chance to clean up
  31.                  * yet because the structure is still in
  32.                  * use. */
  33.     struct Packer *masterPtr;    /* Master window within which this window
  34.                  * is packed (NULL means this window
  35.                  * isn't managed by the packer). */
  36.     struct Packer *nextPtr;    /* Next window packed within same
  37.                  * parent.  List is priority-ordered:
  38.                  * first on list gets packed first. */
  39.     struct Packer *slavePtr;    /* First in list of slaves packed
  40.                  * inside this window (NULL means
  41.                  * no packed slaves). */
  42.     Side side;            /* Side of parent against which
  43.                  * this window is packed. */
  44.     Tk_Anchor anchor;        /* If frame allocated for window is larger
  45.                  * than window needs, this indicates how
  46.                  * where to position window in frame. */
  47.     int padX, padY;        /* Total additional pixels to leave around the
  48.                  * window (half of this space is left on each
  49.                  * side).  This is space *outside* the window:
  50.                  * we'll allocate extra space in frame but
  51.                  * won't enlarge window). */
  52.     int iPadX, iPadY;        /* Total extra pixels to allocate inside the
  53.                  * window (half this amount will appear on
  54.                  * each side). */
  55.     int doubleBw;        /* Twice the window's last known border
  56.                  * width.  If this changes, the window
  57.                  * must be repacked within its parent. */
  58.     int *abortPtr;        /* If non-NULL, it means that there is a nested
  59.                  * call to ArrangePacking already working on
  60.                  * this window.  *abortPtr may be set to 1 to
  61.                  * abort that nested call.  This happens, for
  62.                  * example, if tkwin or any of its slaves
  63.                  * is deleted. */
  64.     int flags;            /* Miscellaneous flags;  see below
  65.                  * for definitions. */
  66. } Packer;
  67.  
  68. /*
  69.  * Flag values for Packer structures:
  70.  *
  71.  * REQUESTED_REPACK:        1 means a Tcl_DoWhenIdle request
  72.  *                has already been made to repack
  73.  *                all the slaves of this window.
  74.  * FILLX:            1 means if frame allocated for window
  75.  *                is wider than window needs, expand window
  76.  *                to fill frame.  0 means don't make window
  77.  *                any larger than needed.
  78.  * FILLY:            Same as FILLX, except for height.
  79.  * EXPAND:            1 means this window's frame will absorb any
  80.  *                extra space in the parent window.
  81.  * OLD_STYLE:            1 means this window is being managed with
  82.  *                the old-style packer algorithms (before
  83.  *                Tk version 3.3).  The main difference is
  84.  *                that padding and filling are done differently.
  85.  * DONT_PROPAGATE:        1 means don't set this window's requested
  86.  *                size.  0 means if this window is a master
  87.  *                then Tk will set its requested size to fit
  88.  *                the needs of its slaves.
  89.  */
  90.  
  91. #define REQUESTED_REPACK    1
  92. #define FILLX            2
  93. #define FILLY            4
  94. #define EXPAND            8
  95. #define OLD_STYLE        16
  96. #define DONT_PROPAGATE        32
  97.  
  98. /*
  99.  * Hash table used to map from Tk_Window tokens to corresponding
  100.  * Packer structures:
  101.  */
  102.  
  103. static Tcl_HashTable packerHashTable;
  104.  
  105. /*
  106.  * Have statics in this module been initialized?
  107.  */
  108.  
  109. static int initialized = 0;
  110.  
  111. /*
  112.  * The following structure is the official type record for the
  113.  * packer:
  114.  */
  115.  
  116. static void        PackReqProc _ANSI_ARGS_((ClientData clientData,
  117.                 Tk_Window tkwin));
  118. static void        PackLostSlaveProc _ANSI_ARGS_((ClientData clientData,
  119.                 Tk_Window tkwin));
  120.  
  121. static Tk_GeomMgr packerType = {
  122.     "pack",            /* name */
  123.     PackReqProc,        /* requestProc */
  124.     PackLostSlaveProc,        /* lostSlaveProc */
  125. };
  126.  
  127. /*
  128.  * Forward declarations for procedures defined later in this file:
  129.  */
  130.  
  131. static void        ArrangePacking _ANSI_ARGS_((ClientData clientData));
  132. static int        ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
  133.                 Tk_Window tkwin, int argc, char *argv[]));
  134. static Packer *        GetPacker _ANSI_ARGS_((Tk_Window tkwin));
  135. static int        PackAfter _ANSI_ARGS_((Tcl_Interp *interp,
  136.                 Packer *prevPtr, Packer *masterPtr, int argc,
  137.                 char **argv));
  138. static void        PackReqProc _ANSI_ARGS_((ClientData clientData,
  139.                 Tk_Window tkwin));
  140. static void        PackStructureProc _ANSI_ARGS_((ClientData clientData,
  141.                 XEvent *eventPtr));
  142. static void        Unlink _ANSI_ARGS_((Packer *packPtr));
  143. static int        XExpansion _ANSI_ARGS_((Packer *slavePtr,
  144.                 int cavityWidth));
  145. static int        YExpansion _ANSI_ARGS_((Packer *slavePtr,
  146.                 int cavityHeight));
  147.  
  148. /*
  149.  *--------------------------------------------------------------
  150.  *
  151.  * Tk_PackCmd --
  152.  *
  153.  *    This procedure is invoked to process the "pack" Tcl command.
  154.  *    See the user documentation for details on what it does.
  155.  *
  156.  * Results:
  157.  *    A standard Tcl result.
  158.  *
  159.  * Side effects:
  160.  *    See the user documentation.
  161.  *
  162.  *--------------------------------------------------------------
  163.  */
  164.  
  165. int
  166. Tk_PackCmd(clientData, interp, argc, argv)
  167.     ClientData clientData;    /* Main window associated with
  168.                  * interpreter. */
  169.     Tcl_Interp *interp;        /* Current interpreter. */
  170.     int argc;            /* Number of arguments. */
  171.     char **argv;        /* Argument strings. */
  172. {
  173.     Tk_Window tkwin = (Tk_Window) clientData;
  174.     size_t length;
  175.     int c;
  176.  
  177.     if ((argc >= 2) && (argv[1][0] == '.')) {
  178.     return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
  179.     }
  180.     if (argc < 3) {
  181.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  182.         argv[0], " option arg ?arg ...?\"", (char *) NULL);
  183.     return TCL_ERROR;
  184.     }
  185.     c = argv[1][0];
  186.     length = strlen(argv[1]);
  187.     if ((c == 'a') && (length >= 2)
  188.         && (strncmp(argv[1], "after", length) == 0)) {
  189.     Packer *prevPtr;
  190.     Tk_Window tkwin2;
  191.  
  192.     tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
  193.     if (tkwin2 == NULL) {
  194.         return TCL_ERROR;
  195.     }
  196.     prevPtr = GetPacker(tkwin2);
  197.     if (prevPtr->masterPtr == NULL) {
  198.         Tcl_AppendResult(interp, "window \"", argv[2],
  199.             "\" isn't packed", (char *) NULL);
  200.         return TCL_ERROR;
  201.     }
  202.     return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3);
  203.     } else if ((c == 'a') && (length >= 2)
  204.         && (strncmp(argv[1], "append", length) == 0)) {
  205.     Packer *masterPtr;
  206.     register Packer *prevPtr;
  207.     Tk_Window tkwin2;
  208.  
  209.     tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
  210.     if (tkwin2 == NULL) {
  211.         return TCL_ERROR;
  212.     }
  213.     masterPtr = GetPacker(tkwin2);
  214.     prevPtr = masterPtr->slavePtr;
  215.     if (prevPtr != NULL) {
  216.         while (prevPtr->nextPtr != NULL) {
  217.         prevPtr = prevPtr->nextPtr;
  218.         }
  219.     }
  220.     return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
  221.     } else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) {
  222.     Packer *packPtr, *masterPtr;
  223.     register Packer *prevPtr;
  224.     Tk_Window tkwin2;
  225.  
  226.     tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
  227.     if (tkwin2 == NULL) {
  228.         return TCL_ERROR;
  229.     }
  230.     packPtr = GetPacker(tkwin2);
  231.     if (packPtr->masterPtr == NULL) {
  232.         Tcl_AppendResult(interp, "window \"", argv[2],
  233.             "\" isn't packed", (char *) NULL);
  234.         return TCL_ERROR;
  235.     }
  236.     masterPtr = packPtr->masterPtr;
  237.     prevPtr = masterPtr->slavePtr;
  238.     if (prevPtr == packPtr) {
  239.         prevPtr = NULL;
  240.     } else {
  241.         for ( ; ; prevPtr = prevPtr->nextPtr) {
  242.         if (prevPtr == NULL) {
  243.             panic("\"pack before\" couldn't find predecessor");
  244.         }
  245.         if (prevPtr->nextPtr == packPtr) {
  246.             break;
  247.         }
  248.         }
  249.     }
  250.     return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3);
  251.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
  252.     if (argv[2][0] != '.') {
  253.         Tcl_AppendResult(interp, "bad argument \"", argv[2],
  254.             "\": must be name of window", (char *) NULL);
  255.         return TCL_ERROR;
  256.     }
  257.     return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
  258.     } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
  259.     Tk_Window slave;
  260.     Packer *slavePtr;
  261.     int i;
  262.  
  263.     for (i = 2; i < argc; i++) {
  264.         slave = Tk_NameToWindow(interp, argv[i], tkwin);
  265.         if (slave == NULL) {
  266.         continue;
  267.         }
  268.         slavePtr = GetPacker(slave);
  269.         if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) {
  270.         Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
  271.             (ClientData) NULL);
  272.         if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
  273.             Tk_UnmaintainGeometry(slavePtr->tkwin,
  274.                 slavePtr->masterPtr->tkwin);
  275.         }
  276.         Unlink(slavePtr);
  277.         Tk_UnmapWindow(slavePtr->tkwin);
  278.         }
  279.     }
  280.     } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
  281.     register Packer *slavePtr;
  282.     Tk_Window slave;
  283.     char buffer[300];
  284.     static char *sideNames[] = {"top", "bottom", "left", "right"};
  285.  
  286.     if (argc != 3) {
  287.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  288.             argv[0], " info window\"", (char *) NULL);
  289.         return TCL_ERROR;
  290.     }
  291.     slave = Tk_NameToWindow(interp, argv[2], tkwin);
  292.     if (slave == NULL) {
  293.         return TCL_ERROR;
  294.     }
  295.     slavePtr = GetPacker(slave);
  296.     if (slavePtr->masterPtr == NULL) {
  297.         Tcl_AppendResult(interp, "window \"", argv[2],
  298.             "\" isn't packed", (char *) NULL);
  299.         return TCL_ERROR;
  300.     }
  301. #ifdef STk_CODE
  302.     Tcl_AppendResult(interp, 
  303.              ":in #.", Tk_PathName(slavePtr->masterPtr->tkwin), " ",
  304.              ":anchor \"", Tk_NameOfAnchor(slavePtr->anchor), "\" ",
  305.              ":expand ",(slavePtr->flags & EXPAND) ? "#t" : "#f", " ",
  306.              ":fill ",
  307.              (char*) NULL);
  308. #else
  309.     Tcl_AppendElement(interp, "-in");
  310.     Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
  311.     Tcl_AppendElement(interp, "-anchor");
  312.     Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor));
  313.     Tcl_AppendResult(interp, " -expand ",
  314.         (slavePtr->flags & EXPAND) ? "1" : "0", " -fill ",
  315.         (char *) NULL);
  316. #endif
  317.     switch (slavePtr->flags & (FILLX|FILLY)) {
  318. #ifdef STk_CODE
  319.         case 0:
  320.         Tcl_AppendResult(interp, "\"none\"", (char *) NULL);
  321.         break;
  322.         case FILLX:
  323.         Tcl_AppendResult(interp, "\"x\"", (char *) NULL);
  324.         break;
  325.         case FILLY:
  326.         Tcl_AppendResult(interp, "\"y\"", (char *) NULL);
  327.         break;
  328.         case FILLX|FILLY:
  329.         Tcl_AppendResult(interp, "\"both\"", (char *) NULL);
  330.         break;
  331. #else
  332.         case 0:
  333.         Tcl_AppendResult(interp, "none", (char *) NULL);
  334.         break;
  335.         case FILLX:
  336.         Tcl_AppendResult(interp, "x", (char *) NULL);
  337.         break;
  338.         case FILLY:
  339.         Tcl_AppendResult(interp, "y", (char *) NULL);
  340.         break;
  341.         case FILLX|FILLY:
  342.         Tcl_AppendResult(interp, "both", (char *) NULL);
  343.         break;
  344. #endif
  345.     }
  346. #ifdef STk_CODE
  347.     sprintf(buffer, " :ipadx %d :ipady %d :padx %d :pady %d",
  348. #else
  349.     sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
  350. #endif
  351.         slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
  352.         slavePtr->padY/2);
  353. #ifdef STk_CODE
  354.     Tcl_AppendResult(interp, buffer, " :side \"",sideNames[slavePtr->side],"\"",
  355. #else
  356.     Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side],
  357. #endif
  358.         (char *) NULL);
  359.     } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
  360.     Tk_Window master;
  361.     Packer *masterPtr;
  362.     int propagate;
  363.  
  364.     if (argc > 4) {
  365.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  366.             argv[0], " propagate window ?boolean?\"", (char *) NULL);
  367.         return TCL_ERROR;
  368.     }
  369.     master = Tk_NameToWindow(interp, argv[2], tkwin);
  370.     if (master == NULL) {
  371.         return TCL_ERROR;
  372.     }
  373.     masterPtr = GetPacker(master);
  374.     if (argc == 3) {
  375. #ifdef STk_CODE
  376.       interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "#t" : "#f";
  377. #else
  378.         if (masterPtr->flags & DONT_PROPAGATE) {
  379.         interp->result = "0";
  380.         } else {
  381.         interp->result = "1";
  382.         }
  383. #endif
  384.         return TCL_OK;
  385.     }
  386.     if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
  387.         return TCL_ERROR;
  388.     }
  389.     if (propagate) {
  390.         masterPtr->flags &= ~DONT_PROPAGATE;
  391.  
  392.         /*
  393.          * Repack the master to allow new geometry information to
  394.          * propagate upwards to the master's master.
  395.          */
  396.  
  397.         if (masterPtr->abortPtr != NULL) {
  398.         *masterPtr->abortPtr = 1;
  399.         }
  400.         if (!(masterPtr->flags & REQUESTED_REPACK)) {
  401.         masterPtr->flags |= REQUESTED_REPACK;
  402.         Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
  403.         }
  404.     } else {
  405.         masterPtr->flags |= DONT_PROPAGATE;
  406.     }
  407.     } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {
  408.     Tk_Window master;
  409.     Packer *masterPtr, *slavePtr;
  410.  
  411.     if (argc != 3) {
  412.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  413.             argv[0], " slaves window\"", (char *) NULL);
  414.         return TCL_ERROR;
  415.     }
  416.     master = Tk_NameToWindow(interp, argv[2], tkwin);
  417.     if (master == NULL) {
  418.         return TCL_ERROR;
  419.     }
  420.     masterPtr = GetPacker(master);
  421. #ifdef STk_CODE
  422.     Tcl_AppendResult(interp, "(", NULL);
  423. #endif
  424.     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
  425.         slavePtr = slavePtr->nextPtr) {
  426.         Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
  427.     }
  428. #ifdef STk_CODE
  429.     Tcl_AppendResult(interp, ")", NULL);
  430. #endif
  431.     } else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) {
  432.     Tk_Window tkwin2;
  433.     Packer *packPtr;
  434.  
  435.     if (argc != 3) {
  436.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  437.             argv[0], " unpack window\"", (char *) NULL);
  438.         return TCL_ERROR;
  439.     }
  440.     tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin);
  441.     if (tkwin2 == NULL) {
  442.         return TCL_ERROR;
  443.     }
  444.     packPtr = GetPacker(tkwin2);
  445.     if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) {
  446.         Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL,
  447.             (ClientData) NULL);
  448.         if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) {
  449.         Tk_UnmaintainGeometry(packPtr->tkwin,
  450.             packPtr->masterPtr->tkwin);
  451.         }
  452.         Unlink(packPtr);
  453.         Tk_UnmapWindow(packPtr->tkwin);
  454.     }
  455.     } else {
  456.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  457.         "\": must be configure, forget, info, ",
  458.         "propagate, or slaves", (char *) NULL);
  459.     return TCL_ERROR;
  460.     }
  461.     return TCL_OK;
  462. }
  463.  
  464. /*
  465.  *--------------------------------------------------------------
  466.  *
  467.  * PackReqProc --
  468.  *
  469.  *    This procedure is invoked by Tk_GeometryRequest for
  470.  *    windows managed by the packer.
  471.  *
  472.  * Results:
  473.  *    None.
  474.  *
  475.  * Side effects:
  476.  *    Arranges for tkwin, and all its managed siblings, to
  477.  *    be re-packed at the next idle point.
  478.  *
  479.  *--------------------------------------------------------------
  480.  */
  481.  
  482.     /* ARGSUSED */
  483. static void
  484. PackReqProc(clientData, tkwin)
  485.     ClientData clientData;    /* Packer's information about
  486.                  * window that got new preferred
  487.                  * geometry.  */
  488.     Tk_Window tkwin;        /* Other Tk-related information
  489.                  * about the window. */
  490. {
  491.     register Packer *packPtr = (Packer *) clientData;
  492.  
  493.     packPtr = packPtr->masterPtr;
  494.     if (!(packPtr->flags & REQUESTED_REPACK)) {
  495.     packPtr->flags |= REQUESTED_REPACK;
  496.     Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
  497.     }
  498. }
  499.  
  500. /*
  501.  *--------------------------------------------------------------
  502.  *
  503.  * PackLostSlaveProc --
  504.  *
  505.  *    This procedure is invoked by Tk whenever some other geometry
  506.  *    claims control over a slave that used to be managed by us.
  507.  *
  508.  * Results:
  509.  *    None.
  510.  *
  511.  * Side effects:
  512.  *    Forgets all packer-related information about the slave.
  513.  *
  514.  *--------------------------------------------------------------
  515.  */
  516.  
  517.     /* ARGSUSED */
  518. static void
  519. PackLostSlaveProc(clientData, tkwin)
  520.     ClientData clientData;    /* Packer structure for slave window that
  521.                  * was stolen away. */
  522.     Tk_Window tkwin;        /* Tk's handle for the slave window. */
  523. {
  524.     register Packer *slavePtr = (Packer *) clientData;
  525.  
  526.     if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
  527.     Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
  528.     }
  529.     Unlink(slavePtr);
  530.     Tk_UnmapWindow(slavePtr->tkwin);
  531. }
  532.  
  533. /*
  534.  *--------------------------------------------------------------
  535.  *
  536.  * ArrangePacking --
  537.  *
  538.  *    This procedure is invoked (using the Tcl_DoWhenIdle
  539.  *    mechanism) to re-layout a set of windows managed by
  540.  *    the packer.  It is invoked at idle time so that a
  541.  *    series of packer requests can be merged into a single
  542.  *    layout operation.
  543.  *
  544.  * Results:
  545.  *    None.
  546.  *
  547.  * Side effects:
  548.  *    The packed slaves of masterPtr may get resized or
  549.  *    moved.
  550.  *
  551.  *--------------------------------------------------------------
  552.  */
  553.  
  554. static void
  555. ArrangePacking(clientData)
  556.     ClientData clientData;    /* Structure describing parent whose slaves
  557.                  * are to be re-layed out. */
  558. {
  559.     register Packer *masterPtr = (Packer *) clientData;
  560.     register Packer *slavePtr;    
  561.     int cavityX, cavityY, cavityWidth, cavityHeight;
  562.                 /* These variables keep track of the
  563.                  * as-yet-unallocated space remaining in
  564.                  * the middle of the parent window. */
  565.     int frameX, frameY, frameWidth, frameHeight;
  566.                 /* These variables keep track of the frame
  567.                  * allocated to the current window. */
  568.     int x, y, width, height;    /* These variables are used to hold the
  569.                  * actual geometry of the current window. */
  570.     int intBWidth;        /* Width of internal border in parent window,
  571.                  * if any. */
  572.     int abort;            /* May get set to non-zero to abort this
  573.                  * repacking operation. */
  574.     int borderX, borderY;
  575.     int maxWidth, maxHeight, tmp;
  576.  
  577.     masterPtr->flags &= ~REQUESTED_REPACK;
  578.  
  579.     /*
  580.      * If the parent has no slaves anymore, then don't do anything
  581.      * at all:  just leave the parent's size as-is.
  582.      */
  583.  
  584.     if (masterPtr->slavePtr == NULL) {
  585.     return;
  586.     }
  587.  
  588.     /*
  589.      * Abort any nested call to ArrangePacking for this window, since
  590.      * we'll do everything necessary here, and set up so this call
  591.      * can be aborted if necessary.  
  592.      */
  593.  
  594.     if (masterPtr->abortPtr != NULL) {
  595.     *masterPtr->abortPtr = 1;
  596.     }
  597.     masterPtr->abortPtr = &abort;
  598.     abort = 0;
  599.     Tcl_Preserve((ClientData) masterPtr);
  600.  
  601.     /*
  602.      * Pass #1: scan all the slaves to figure out the total amount
  603.      * of space needed.  Two separate width and height values are
  604.      * computed:
  605.      *
  606.      * width -        Holds the sum of the widths (plus padding) of
  607.      *            all the slaves seen so far that were packed LEFT
  608.      *            or RIGHT.
  609.      * height -        Holds the sum of the heights (plus padding) of
  610.      *            all the slaves seen so far that were packed TOP
  611.      *            or BOTTOM.
  612.      *
  613.      * maxWidth -    Gradually builds up the width needed by the master
  614.      *            to just barely satisfy all the slave's needs.  For
  615.      *            each slave, the code computes the width needed for
  616.      *            all the slaves so far and updates maxWidth if the
  617.      *            new value is greater.
  618.      * maxHeight -    Same as maxWidth, except keeps height info.
  619.      */
  620.  
  621.     intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
  622.     width = height = maxWidth = maxHeight = 2*intBWidth;
  623.     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
  624.         slavePtr = slavePtr->nextPtr) {
  625.     if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
  626.         tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
  627.             + slavePtr->padX + slavePtr->iPadX + width;
  628.         if (tmp > maxWidth) {
  629.         maxWidth = tmp;
  630.         }
  631.         height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
  632.             + slavePtr->padY + slavePtr->iPadY;
  633.     } else {
  634.         tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
  635.             + slavePtr->padY + slavePtr->iPadY + height;
  636.         if (tmp > maxHeight) {
  637.         maxHeight = tmp;
  638.         }
  639.         width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
  640.             + slavePtr->padX + slavePtr->iPadX;
  641.     }
  642.     }
  643.     if (width > maxWidth) {
  644.     maxWidth = width;
  645.     }
  646.     if (height > maxHeight) {
  647.     maxHeight = height;
  648.     }
  649.  
  650.     /*
  651.      * If the total amount of space needed in the parent window has
  652.      * changed, and if we're propagating geometry information, then
  653.      * notify the next geometry manager up and requeue ourselves to
  654.      * start again after the parent has had a chance to
  655.      * resize us.
  656.      */
  657.  
  658.     if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin))
  659.         || (maxHeight != Tk_ReqHeight(masterPtr->tkwin)))
  660.         && !(masterPtr->flags & DONT_PROPAGATE)) {
  661.     Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight);
  662.     masterPtr->flags |= REQUESTED_REPACK;
  663.     Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
  664.     goto done;
  665.     }
  666.  
  667.     /*
  668.      * Pass #2: scan the slaves a second time assigning
  669.      * new sizes.  The "cavity" variables keep track of the
  670.      * unclaimed space in the cavity of the window;  this
  671.      * shrinks inward as we allocate windows around the
  672.      * edges.  The "frame" variables keep track of the space
  673.      * allocated to the current window and its frame.  The
  674.      * current window is then placed somewhere inside the
  675.      * frame, depending on anchor.
  676.      */
  677.  
  678.     cavityX = cavityY = x = y = intBWidth;
  679.     cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth;
  680.     cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
  681.     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
  682.         slavePtr = slavePtr->nextPtr) {
  683.     if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
  684.         frameWidth = cavityWidth;
  685.         frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
  686.             + slavePtr->padY + slavePtr->iPadY;
  687.         if (slavePtr->flags & EXPAND) {
  688.         frameHeight += YExpansion(slavePtr, cavityHeight);
  689.         }
  690.         cavityHeight -= frameHeight;
  691.         if (cavityHeight < 0) {
  692.         frameHeight += cavityHeight;
  693.         cavityHeight = 0;
  694.         }
  695.         frameX = cavityX;
  696.         if (slavePtr->side == TOP) {
  697.         frameY = cavityY;
  698.         cavityY += frameHeight;
  699.         } else {
  700.         frameY = cavityY + cavityHeight;
  701.         }
  702.     } else {
  703.         frameHeight = cavityHeight;
  704.         frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
  705.             + slavePtr->padX + slavePtr->iPadX;
  706.         if (slavePtr->flags & EXPAND) {
  707.         frameWidth += XExpansion(slavePtr, cavityWidth);
  708.         }
  709.         cavityWidth -= frameWidth;
  710.         if (cavityWidth < 0) {
  711.         frameWidth += cavityWidth;
  712.         cavityWidth = 0;
  713.         }
  714.         frameY = cavityY;
  715.         if (slavePtr->side == LEFT) {
  716.         frameX = cavityX;
  717.         cavityX += frameWidth;
  718.         } else {
  719.         frameX = cavityX + cavityWidth;
  720.         }
  721.     }
  722.  
  723.     /*
  724.      * Now that we've got the size of the frame for the window,
  725.      * compute the window's actual size and location using the
  726.      * fill, padding, and frame factors.  The variables "borderX"
  727.      * and "borderY" are used to handle the differences between
  728.      * old-style packing and the new style (in old-style, iPadX
  729.      * and iPadY are always zero and padding is completely ignored
  730.      * except when computing frame size).
  731.      */
  732.  
  733.     if (slavePtr->flags & OLD_STYLE) {
  734.         borderX = borderY = 0;
  735.     } else {
  736.         borderX = slavePtr->padX;
  737.         borderY = slavePtr->padY;
  738.     }
  739.     width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
  740.         + slavePtr->iPadX;
  741.     if ((slavePtr->flags & FILLX)
  742.         || (width > (frameWidth - borderX))) {
  743.         width = frameWidth - borderX;
  744.     }
  745.     height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
  746.         + slavePtr->iPadY;
  747.     if ((slavePtr->flags & FILLY)
  748.         || (height > (frameHeight - borderY))) {
  749.         height = frameHeight - borderY;
  750.     }
  751.     borderX /= 2;
  752.     borderY /= 2;
  753.     switch (slavePtr->anchor) {
  754.         case TK_ANCHOR_N:
  755.         x = frameX + (frameWidth - width)/2;
  756.         y = frameY + borderY;
  757.         break;
  758.         case TK_ANCHOR_NE:
  759.         x = frameX + frameWidth - width - borderX;
  760.         y = frameY + borderY;
  761.         break;
  762.         case TK_ANCHOR_E:
  763.         x = frameX + frameWidth - width - borderX;
  764.         y = frameY + (frameHeight - height)/2;
  765.         break;
  766.         case TK_ANCHOR_SE:
  767.         x = frameX + frameWidth - width - borderX;
  768.         y = frameY + frameHeight - height - borderY;
  769.         break;
  770.         case TK_ANCHOR_S:
  771.         x = frameX + (frameWidth - width)/2;
  772.         y = frameY + frameHeight - height - borderY;
  773.         break;
  774.         case TK_ANCHOR_SW:
  775.         x = frameX + borderX;
  776.         y = frameY + frameHeight - height - borderY;
  777.         break;
  778.         case TK_ANCHOR_W:
  779.         x = frameX + borderX;
  780.         y = frameY + (frameHeight - height)/2;
  781.         break;
  782.         case TK_ANCHOR_NW:
  783.         x = frameX + borderX;
  784.         y = frameY + borderY;
  785.         break;
  786.         case TK_ANCHOR_CENTER:
  787.         x = frameX + (frameWidth - width)/2;
  788.         y = frameY + (frameHeight - height)/2;
  789.         break;
  790.         default:
  791.         panic("bad frame factor in ArrangePacking");
  792.     }
  793.     width -= slavePtr->doubleBw;
  794.     height -= slavePtr->doubleBw;
  795.  
  796.     /*
  797.      * The final step is to set the position, size, and mapped/unmapped
  798.      * state of the slave.  If the slave is a child of the master, then
  799.      * do this here.  Otherwise let Tk_MaintainGeometry do the work.
  800.      */
  801.  
  802.     if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
  803.         if ((width <= 0) || (height <= 0)) {
  804.         Tk_UnmapWindow(slavePtr->tkwin);
  805.         } else {
  806.         if ((x != Tk_X(slavePtr->tkwin))
  807.             || (y != Tk_Y(slavePtr->tkwin))
  808.             || (width != Tk_Width(slavePtr->tkwin))
  809.             || (height != Tk_Height(slavePtr->tkwin))) {
  810.             Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
  811.         }
  812.         if (abort) {
  813.             goto done;
  814.         }
  815.  
  816.         /*
  817.          * Don't map the slave if the master isn't mapped: wait
  818.          * until the master gets mapped later.
  819.          */
  820.  
  821.         if (Tk_IsMapped(masterPtr->tkwin)) {
  822.             Tk_MapWindow(slavePtr->tkwin);
  823.         }
  824.         }
  825.     } else {
  826.         if ((width <= 0) || (height <= 0)) {
  827.         Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
  828.         Tk_UnmapWindow(slavePtr->tkwin);
  829.         } else {
  830.         Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
  831.             x, y, width, height);
  832.         }
  833.     }
  834.  
  835.     /*
  836.      * Changes to the window's structure could cause almost anything
  837.      * to happen, including deleting the parent or child.  If this
  838.      * happens, we'll be told to abort.
  839.      */
  840.  
  841.     if (abort) {
  842.         goto done;
  843.     }
  844.     }
  845.  
  846.     done:
  847.     masterPtr->abortPtr = NULL;
  848.     Tcl_Release((ClientData) masterPtr);
  849. }
  850.  
  851. /*
  852.  *----------------------------------------------------------------------
  853.  *
  854.  * XExpansion --
  855.  *
  856.  *    Given a list of packed slaves, the first of which is packed
  857.  *    on the left or right and is expandable, compute how much to
  858.  *    expand the child.
  859.  *
  860.  * Results:
  861.  *    The return value is the number of additional pixels to give to
  862.  *    the child.
  863.  *
  864.  * Side effects:
  865.  *    None.
  866.  *
  867.  *----------------------------------------------------------------------
  868.  */
  869.  
  870. static int
  871. XExpansion(slavePtr, cavityWidth)
  872.     register Packer *slavePtr;        /* First in list of remaining
  873.                      * slaves. */
  874.     int cavityWidth;            /* Horizontal space left for all
  875.                      * remaining slaves. */
  876. {
  877.     int numExpand, minExpand, curExpand;
  878.     int childWidth;
  879.  
  880.     /*
  881.      * This procedure is tricky because windows packed top or bottom can
  882.      * be interspersed among expandable windows packed left or right.
  883.      * Scan through the list, keeping a running sum of the widths of
  884.      * all left and right windows (actually, count the cavity space not
  885.      * allocated) and a running count of all expandable left and right
  886.      * windows.  At each top or bottom window, and at the end of the
  887.      * list, compute the expansion factor that seems reasonable at that
  888.      * point.  Return the smallest factor seen at any of these points.
  889.      */
  890.  
  891.     minExpand = cavityWidth;
  892.     numExpand = 0;
  893.     for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
  894.     childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw
  895.         + slavePtr->padX + slavePtr->iPadX;
  896.     if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) {
  897.         curExpand = (cavityWidth - childWidth)/numExpand;
  898.         if (curExpand < minExpand) {
  899.         minExpand = curExpand;
  900.         }
  901.     } else {
  902.         cavityWidth -= childWidth;
  903.         if (slavePtr->flags & EXPAND) {
  904.         numExpand++;
  905.         }
  906.     }
  907.     }
  908.     curExpand = cavityWidth/numExpand;
  909.     if (curExpand < minExpand) {
  910.     minExpand = curExpand;
  911.     }
  912.     return (minExpand < 0) ? 0 : minExpand;
  913. }
  914.  
  915. /*
  916.  *----------------------------------------------------------------------
  917.  *
  918.  * YExpansion --
  919.  *
  920.  *    Given a list of packed slaves, the first of which is packed
  921.  *    on the top or bottom and is expandable, compute how much to
  922.  *    expand the child.
  923.  *
  924.  * Results:
  925.  *    The return value is the number of additional pixels to give to
  926.  *    the child.
  927.  *
  928.  * Side effects:
  929.  *    None.
  930.  *
  931.  *----------------------------------------------------------------------
  932.  */
  933.  
  934. static int
  935. YExpansion(slavePtr, cavityHeight)
  936.     register Packer *slavePtr;        /* First in list of remaining
  937.                      * slaves. */
  938.     int cavityHeight;            /* Vertical space left for all
  939.                      * remaining slaves. */
  940. {
  941.     int numExpand, minExpand, curExpand;
  942.     int childHeight;
  943.  
  944.     /*
  945.      * See comments for XExpansion.
  946.      */
  947.  
  948.     minExpand = cavityHeight;
  949.     numExpand = 0;
  950.     for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) {
  951.     childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw
  952.         + slavePtr->padY + slavePtr->iPadY;
  953.     if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) {
  954.         curExpand = (cavityHeight - childHeight)/numExpand;
  955.         if (curExpand < minExpand) {
  956.         minExpand = curExpand;
  957.         }
  958.     } else {
  959.         cavityHeight -= childHeight;
  960.         if (slavePtr->flags & EXPAND) {
  961.         numExpand++;
  962.         }
  963.     }
  964.     }
  965.     curExpand = cavityHeight/numExpand;
  966.     if (curExpand < minExpand) {
  967.     minExpand = curExpand;
  968.     }
  969.     return (minExpand < 0) ? 0 : minExpand;
  970. }
  971.  
  972. /*
  973.  *--------------------------------------------------------------
  974.  *
  975.  * GetPacker --
  976.  *
  977.  *    This internal procedure is used to locate a Packer
  978.  *    structure for a given window, creating one if one
  979.  *    doesn't exist already.
  980.  *
  981.  * Results:
  982.  *    The return value is a pointer to the Packer structure
  983.  *    corresponding to tkwin.
  984.  *
  985.  * Side effects:
  986.  *    A new packer structure may be created.  If so, then
  987.  *    a callback is set up to clean things up when the
  988.  *    window is deleted.
  989.  *
  990.  *--------------------------------------------------------------
  991.  */
  992.  
  993. static Packer *
  994. GetPacker(tkwin)
  995.     Tk_Window tkwin;        /* Token for window for which
  996.                  * packer structure is desired. */
  997. {
  998.     register Packer *packPtr;
  999.     Tcl_HashEntry *hPtr;
  1000.     int new;
  1001.  
  1002.     if (!initialized) {
  1003.     initialized = 1;
  1004.     Tcl_InitHashTable(&packerHashTable, TCL_ONE_WORD_KEYS);
  1005.     }
  1006.  
  1007.     /*
  1008.      * See if there's already packer for this window.  If not,
  1009.      * then create a new one.
  1010.      */
  1011.  
  1012.     hPtr = Tcl_CreateHashEntry(&packerHashTable, (char *) tkwin, &new);
  1013.     if (!new) {
  1014.     return (Packer *) Tcl_GetHashValue(hPtr);
  1015.     }
  1016.     packPtr = (Packer *) ckalloc(sizeof(Packer));
  1017.     packPtr->tkwin = tkwin;
  1018.     packPtr->masterPtr = NULL;
  1019.     packPtr->nextPtr = NULL;
  1020.     packPtr->slavePtr = NULL;
  1021.     packPtr->side = TOP;
  1022.     packPtr->anchor = TK_ANCHOR_CENTER;
  1023.     packPtr->padX = packPtr->padY = 0;
  1024.     packPtr->iPadX = packPtr->iPadY = 0;
  1025.     packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
  1026.     packPtr->abortPtr = NULL;
  1027.     packPtr->flags = 0;
  1028.     Tcl_SetHashValue(hPtr, packPtr);
  1029.     Tk_CreateEventHandler(tkwin, StructureNotifyMask,
  1030.         PackStructureProc, (ClientData) packPtr);
  1031.     return packPtr;
  1032. }
  1033.  
  1034. /*
  1035.  *--------------------------------------------------------------
  1036.  *
  1037.  * PackAfter --
  1038.  *
  1039.  *    This procedure does most of the real work of adding
  1040.  *    one or more windows into the packing order for its parent.
  1041.  *
  1042.  * Results:
  1043.  *    A standard Tcl return value.
  1044.  *
  1045.  * Side effects:
  1046.  *    The geometry of the specified windows may change, both now and
  1047.  *    again in the future.
  1048.  *
  1049.  *--------------------------------------------------------------
  1050.  */
  1051.  
  1052. static int
  1053. PackAfter(interp, prevPtr, masterPtr, argc, argv)
  1054.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  1055.     Packer *prevPtr;        /* Pack windows in argv just after this
  1056.                  * window;  NULL means pack as first
  1057.                  * child of masterPtr. */
  1058.     Packer *masterPtr;        /* Master in which to pack windows. */
  1059.     int argc;            /* Number of elements in argv. */
  1060.     char **argv;        /* Array of lists, each containing 2
  1061.                  * elements:  window name and side
  1062.                  * against which to pack. */
  1063. {
  1064.     register Packer *packPtr;
  1065.     Tk_Window tkwin, ancestor, parent;
  1066.     size_t length;
  1067.     char **options;
  1068.     int index, tmp, optionCount, c;
  1069.  
  1070.     /*
  1071.      * Iterate over all of the window specifiers, each consisting of
  1072.      * two arguments.  The first argument contains the window name and
  1073.      * the additional arguments contain options such as "top" or
  1074.      * "padx 20".
  1075.      */
  1076.  
  1077.     for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) {
  1078.     if (argc < 2) {
  1079.         Tcl_AppendResult(interp, "wrong # args: window \"",
  1080.             argv[0], "\" should be followed by options",
  1081.             (char *) NULL);
  1082.         return TCL_ERROR;
  1083.     }
  1084.  
  1085.     /*
  1086.      * Find the packer for the window to be packed, and make sure
  1087.      * that the window in which it will be packed is either its
  1088.      * or a descendant of its parent.
  1089.      */
  1090.  
  1091.     tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin);
  1092.     if (tkwin == NULL) {
  1093.         return TCL_ERROR;
  1094.     }
  1095.  
  1096.     parent = Tk_Parent(tkwin);
  1097.     for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
  1098.         if (ancestor == parent) {
  1099.         break;
  1100.         }
  1101.         if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
  1102.         badWindow:
  1103.         Tcl_AppendResult(interp, "can't pack ", argv[0],
  1104.             " inside ", Tk_PathName(masterPtr->tkwin),
  1105.             (char *) NULL);
  1106.         return TCL_ERROR;
  1107.         }
  1108.     }
  1109.     if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) {
  1110.         goto badWindow;
  1111.     }
  1112.     if (tkwin == masterPtr->tkwin) {
  1113.         goto badWindow;
  1114.     }
  1115.     packPtr = GetPacker(tkwin);
  1116.  
  1117.     /*
  1118.      * Process options for this window.
  1119.      */
  1120.  
  1121.     if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) {
  1122.         return TCL_ERROR;
  1123.     }
  1124.     packPtr->side = TOP;
  1125.     packPtr->anchor = TK_ANCHOR_CENTER;
  1126.     packPtr->padX = packPtr->padY = 0;
  1127.     packPtr->iPadX = packPtr->iPadY = 0;
  1128.     packPtr->flags &= ~(FILLX|FILLY|EXPAND);
  1129.     packPtr->flags |= OLD_STYLE;
  1130.     for (index = 0 ; index < optionCount; index++) {
  1131.         char *curOpt = options[index];
  1132.  
  1133.         c = curOpt[0];
  1134.         length = strlen(curOpt);
  1135.  
  1136.         if ((c == 't')
  1137.             && (strncmp(curOpt, "top", length)) == 0) {
  1138.         packPtr->side = TOP;
  1139.         } else if ((c == 'b')
  1140.             && (strncmp(curOpt, "bottom", length)) == 0) {
  1141.         packPtr->side = BOTTOM;
  1142.         } else if ((c == 'l')
  1143.             && (strncmp(curOpt, "left", length)) == 0) {
  1144.         packPtr->side = LEFT;
  1145.         } else if ((c == 'r')
  1146.             && (strncmp(curOpt, "right", length)) == 0) {
  1147.         packPtr->side = RIGHT;
  1148.         } else if ((c == 'e')
  1149.             && (strncmp(curOpt, "expand", length)) == 0) {
  1150.         packPtr->flags |= EXPAND;
  1151.         } else if ((c == 'f')
  1152.             && (strcmp(curOpt, "fill")) == 0) {
  1153.         packPtr->flags |= FILLX|FILLY;
  1154.         } else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) {
  1155.         packPtr->flags |= FILLX;
  1156.         } else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) {
  1157.         packPtr->flags |= FILLY;
  1158.         } else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) {
  1159.         if (optionCount < (index+2)) {
  1160.             missingPad:
  1161.             Tcl_AppendResult(interp, "wrong # args: \"", curOpt,
  1162.                 "\" option must be followed by screen distance",
  1163.                 (char *) NULL);
  1164.             goto error;
  1165.         }
  1166.         if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
  1167.             != TCL_OK) || (tmp < 0)) {
  1168.             badPad:
  1169.             Tcl_AppendResult(interp, "bad pad value \"",
  1170.                 options[index+1],
  1171.                 "\": must be positive screen distance",
  1172.                 (char *) NULL);
  1173.             goto error;
  1174.         }
  1175.         packPtr->padX = tmp;
  1176.         packPtr->iPadX = 0;
  1177.         index++;
  1178.         } else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) {
  1179.         if (optionCount < (index+2)) {
  1180.             goto missingPad;
  1181.         }
  1182.         if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp)
  1183.             != TCL_OK) || (tmp < 0)) {
  1184.             goto badPad;
  1185.         }
  1186.         packPtr->padY = tmp;
  1187.         packPtr->iPadY = 0;
  1188.         index++;
  1189.         } else if ((c == 'f') && (length > 1)
  1190.             && (strncmp(curOpt, "frame", length) == 0)) {
  1191.         if (optionCount < (index+2)) {
  1192.             Tcl_AppendResult(interp, "wrong # args: \"frame\" ",
  1193.                 "option must be followed by anchor point",
  1194.                 (char *) NULL);
  1195.             goto error;
  1196.         }
  1197.         if (Tk_GetAnchor(interp, options[index+1],
  1198.             &packPtr->anchor) != TCL_OK) {
  1199.             goto error;
  1200.         }
  1201.         index++;
  1202.         } else {
  1203.         Tcl_AppendResult(interp, "bad option \"", curOpt,
  1204.             "\": should be top, bottom, left, right, ",
  1205.             "expand, fill, fillx, filly, padx, pady, or frame",
  1206.             (char *) NULL);
  1207.         goto error;
  1208.         }
  1209.     }
  1210.  
  1211.     if (packPtr != prevPtr) {
  1212.  
  1213.         /*
  1214.          * Unpack this window if it's currently packed.
  1215.          */
  1216.  
  1217.         if (packPtr->masterPtr != NULL) {
  1218.         if ((packPtr->masterPtr != masterPtr) &&
  1219.             (packPtr->masterPtr->tkwin
  1220.             != Tk_Parent(packPtr->tkwin))) {
  1221.             Tk_UnmaintainGeometry(packPtr->tkwin,
  1222.                 packPtr->masterPtr->tkwin);
  1223.         }
  1224.         Unlink(packPtr);
  1225.         }
  1226.     
  1227.         /*
  1228.          * Add the window in the correct place in its parent's
  1229.          * packing order, then make sure that the window is
  1230.          * managed by us.
  1231.          */
  1232.  
  1233.         packPtr->masterPtr = masterPtr;
  1234.         if (prevPtr == NULL) {
  1235.         packPtr->nextPtr = masterPtr->slavePtr;
  1236.         masterPtr->slavePtr = packPtr;
  1237.         } else {
  1238.         packPtr->nextPtr = prevPtr->nextPtr;
  1239.         prevPtr->nextPtr = packPtr;
  1240.         }
  1241.         Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr);
  1242.     }
  1243.     ckfree((char *) options);
  1244.     }
  1245.  
  1246.     /*
  1247.      * Arrange for the parent to be re-packed at the first
  1248.      * idle moment.
  1249.      */
  1250.  
  1251.     if (masterPtr->abortPtr != NULL) {
  1252.     *masterPtr->abortPtr = 1;
  1253.     }
  1254.     if (!(masterPtr->flags & REQUESTED_REPACK)) {
  1255.     masterPtr->flags |= REQUESTED_REPACK;
  1256.     Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
  1257.     }
  1258.     return TCL_OK;
  1259.  
  1260.     error:
  1261.     ckfree((char *) options);
  1262.     return TCL_ERROR;
  1263. }
  1264.  
  1265. /*
  1266.  *----------------------------------------------------------------------
  1267.  *
  1268.  * Unlink --
  1269.  *
  1270.  *    Remove a packer from its parent's list of slaves.
  1271.  *
  1272.  * Results:
  1273.  *    None.
  1274.  *
  1275.  * Side effects:
  1276.  *    The parent will be scheduled for repacking.
  1277.  *
  1278.  *----------------------------------------------------------------------
  1279.  */
  1280.  
  1281. static void
  1282. Unlink(packPtr)
  1283.     register Packer *packPtr;        /* Window to unlink. */
  1284. {
  1285.     register Packer *masterPtr, *packPtr2;
  1286.  
  1287.     masterPtr = packPtr->masterPtr;
  1288.     if (masterPtr == NULL) {
  1289.     return;
  1290.     }
  1291.     if (masterPtr->slavePtr == packPtr) {
  1292.     masterPtr->slavePtr = packPtr->nextPtr;
  1293.     } else {
  1294.     for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) {
  1295.         if (packPtr2 == NULL) {
  1296.         panic("Unlink couldn't find previous window");
  1297.         }
  1298.         if (packPtr2->nextPtr == packPtr) {
  1299.         packPtr2->nextPtr = packPtr->nextPtr;
  1300.         break;
  1301.         }
  1302.     }
  1303.     }
  1304.     if (!(masterPtr->flags & REQUESTED_REPACK)) {
  1305.     masterPtr->flags |= REQUESTED_REPACK;
  1306.     Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
  1307.     }
  1308.     if (masterPtr->abortPtr != NULL) {
  1309.     *masterPtr->abortPtr = 1;
  1310.     }
  1311.  
  1312.     packPtr->masterPtr = NULL;
  1313. }
  1314.  
  1315. /*
  1316.  *----------------------------------------------------------------------
  1317.  *
  1318.  * DestroyPacker --
  1319.  *
  1320.  *    This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  1321.  *    to clean up the internal structure of a packer at a safe time
  1322.  *    (when no-one is using it anymore).
  1323.  *
  1324.  * Results:
  1325.  *    None.
  1326.  *
  1327.  * Side effects:
  1328.  *    Everything associated with the packer is freed up.
  1329.  *
  1330.  *----------------------------------------------------------------------
  1331.  */
  1332.  
  1333. static void
  1334. DestroyPacker(memPtr)
  1335.     char *memPtr;        /* Info about packed window that
  1336.                  * is now dead. */
  1337. {
  1338.     register Packer *packPtr = (Packer *) memPtr;
  1339.     ckfree((char *) packPtr);
  1340. }
  1341.  
  1342. /*
  1343.  *----------------------------------------------------------------------
  1344.  *
  1345.  * PackStructureProc --
  1346.  *
  1347.  *    This procedure is invoked by the Tk event dispatcher in response
  1348.  *    to StructureNotify events.
  1349.  *
  1350.  * Results:
  1351.  *    None.
  1352.  *
  1353.  * Side effects:
  1354.  *    If a window was just deleted, clean up all its packer-related
  1355.  *    information.  If it was just resized, repack its slaves, if
  1356.  *    any.
  1357.  *
  1358.  *----------------------------------------------------------------------
  1359.  */
  1360.  
  1361. static void
  1362. PackStructureProc(clientData, eventPtr)
  1363.     ClientData clientData;        /* Our information about window
  1364.                      * referred to by eventPtr. */
  1365.     XEvent *eventPtr;            /* Describes what just happened. */
  1366. {
  1367.     register Packer *packPtr = (Packer *) clientData;
  1368.     if (eventPtr->type == ConfigureNotify) {
  1369.     if ((packPtr->slavePtr != NULL)
  1370.         && !(packPtr->flags & REQUESTED_REPACK)) {
  1371.         packPtr->flags |= REQUESTED_REPACK;
  1372.         Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
  1373.     }
  1374.     if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) {
  1375.         if ((packPtr->masterPtr != NULL)
  1376.             && !(packPtr->masterPtr->flags & REQUESTED_REPACK)) {
  1377.         packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width;
  1378.         packPtr->masterPtr->flags |= REQUESTED_REPACK;
  1379.         Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr);
  1380.         }
  1381.     }
  1382.     } else if (eventPtr->type == DestroyNotify) {
  1383.     register Packer *slavePtr, *nextPtr;
  1384.  
  1385.     if (packPtr->masterPtr != NULL) {
  1386.         Unlink(packPtr);
  1387.     }
  1388.     for (slavePtr = packPtr->slavePtr; slavePtr != NULL;
  1389.         slavePtr = nextPtr) {
  1390.         Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL,
  1391.             (ClientData) NULL);
  1392.         Tk_UnmapWindow(slavePtr->tkwin);
  1393.         slavePtr->masterPtr = NULL;
  1394.         nextPtr = slavePtr->nextPtr;
  1395.         slavePtr->nextPtr = NULL;
  1396.     }
  1397.     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&packerHashTable,
  1398.         (char *) packPtr->tkwin));
  1399.     if (packPtr->flags & REQUESTED_REPACK) {
  1400.         Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr);
  1401.     }
  1402.     packPtr->tkwin = NULL;
  1403.     Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker);
  1404.     } else if (eventPtr->type == MapNotify) {
  1405.     /*
  1406.      * When a master gets mapped, must redo the geometry computation
  1407.      * so that all of its slaves get remapped.
  1408.      */
  1409.  
  1410.     if ((packPtr->slavePtr != NULL)
  1411.         && !(packPtr->flags & REQUESTED_REPACK)) {
  1412.         packPtr->flags |= REQUESTED_REPACK;
  1413.         Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr);
  1414.     }
  1415.     } else if (eventPtr->type == UnmapNotify) {
  1416.     Packer *packPtr2;
  1417.  
  1418.     /*
  1419.      * Unmap all of the slaves when the master gets unmapped,
  1420.      * so that they don't bother to keep redisplaying
  1421.      * themselves.
  1422.      */
  1423.  
  1424.     for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL;
  1425.         packPtr2 = packPtr2->nextPtr) {
  1426.         Tk_UnmapWindow(packPtr2->tkwin);
  1427.     }
  1428.     }
  1429. }
  1430.  
  1431. /*
  1432.  *----------------------------------------------------------------------
  1433.  *
  1434.  * ConfigureSlaves --
  1435.  *
  1436.  *    This implements the guts of the "pack configure" command.  Given
  1437.  *    a list of slaves and configuration options, it arranges for the
  1438.  *    packer to manage the slaves and sets the specified options.
  1439.  *
  1440.  * Results:
  1441.  *    TCL_OK is returned if all went well.  Otherwise, TCL_ERROR is
  1442.  *    returned and interp->result is set to contain an error message.
  1443.  *
  1444.  * Side effects:
  1445.  *    Slave windows get taken over by the packer.
  1446.  *
  1447.  *----------------------------------------------------------------------
  1448.  */
  1449.  
  1450. static int
  1451. ConfigureSlaves(interp, tkwin, argc, argv)
  1452.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  1453.     Tk_Window tkwin;        /* Any window in application containing
  1454.                  * slaves.  Used to look up slave names. */
  1455.     int argc;            /* Number of elements in argv. */
  1456.     char *argv[];        /* Argument strings:  contains one or more
  1457.                  * window names followed by any number
  1458.                  * of "option value" pairs.  Caller must
  1459.                  * make sure that there is at least one
  1460.                  * window name. */
  1461. {
  1462.     Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr;
  1463.     Tk_Window other, slave, parent, ancestor;
  1464.     int i, j, numWindows, c, tmp, positionGiven;
  1465.     size_t length;
  1466.  
  1467.     /*
  1468.      * Find out how many windows are specified.
  1469.      */
  1470.  
  1471.     for (numWindows = 0; numWindows < argc; numWindows++) {
  1472.     if (argv[numWindows][0] != '.') {
  1473.         break;
  1474.     }
  1475.     }
  1476.  
  1477.     /*
  1478.      * Iterate over all of the slave windows, parsing the configuration
  1479.      * options for each slave.  It's a bit wasteful to re-parse the
  1480.      * options for each slave, but things get too messy if we try to
  1481.      * parse the arguments just once at the beginning.  For example,
  1482.      * if a slave already is packed we want to just change a few
  1483.      * existing values without resetting everything.  If there are
  1484.      * multiple windows, the -after, -before, and -in options only
  1485.      * get processed for the first window.
  1486.      */
  1487.  
  1488.     masterPtr = NULL;
  1489.     prevPtr = NULL;
  1490.     positionGiven = 0;
  1491.     for (j = 0; j < numWindows; j++) {
  1492.     slave = Tk_NameToWindow(interp, argv[j], tkwin);
  1493.     if (slave == NULL) {
  1494.         return TCL_ERROR;
  1495.     }
  1496.     if (Tk_IsTopLevel(slave)) {
  1497.         Tcl_AppendResult(interp, "can't pack \"", argv[j],
  1498.             "\": it's a top-level window", (char *) NULL);
  1499.         return TCL_ERROR;
  1500.     }
  1501.     slavePtr = GetPacker(slave);
  1502.     slavePtr->flags &= ~OLD_STYLE;
  1503.  
  1504.     /*
  1505.      * If the slave isn't currently packed, reset all of its
  1506.      * configuration information to default values (there could
  1507.      * be old values left from a previous packing).
  1508.      */
  1509.  
  1510.     if (slavePtr->masterPtr == NULL) {
  1511.         slavePtr->side = TOP;
  1512.         slavePtr->anchor = TK_ANCHOR_CENTER;
  1513.         slavePtr->padX = slavePtr->padY = 0;
  1514.         slavePtr->iPadX = slavePtr->iPadY = 0;
  1515.         slavePtr->flags &= ~(FILLX|FILLY|EXPAND);
  1516.     }
  1517.  
  1518.     for (i = numWindows; i < argc; i+=2) {
  1519.         if ((i+2) > argc) {
  1520.         Tcl_AppendResult(interp, "extra option \"", argv[i],
  1521.             "\" (option with no value?)", (char *) NULL);
  1522.         return TCL_ERROR;
  1523.         }
  1524.         length = strlen(argv[i]);
  1525.         if (length < 2) {
  1526.         goto badOption;
  1527.         }
  1528.         c = argv[i][1];
  1529.         if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0)
  1530.             && (length >= 2)) {
  1531.         if (j == 0) {
  1532.             other = Tk_NameToWindow(interp, argv[i+1], tkwin);
  1533.             if (other == NULL) {
  1534.             return TCL_ERROR;
  1535.             }
  1536.             prevPtr = GetPacker(other);
  1537.             if (prevPtr->masterPtr == NULL) {
  1538.             notPacked:
  1539.             Tcl_AppendResult(interp, "window \"", argv[i+1],
  1540.                 "\" isn't packed", (char *) NULL);
  1541.             return TCL_ERROR;
  1542.             }
  1543.             masterPtr = prevPtr->masterPtr;
  1544.             positionGiven = 1;
  1545.         }
  1546.         } else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0)
  1547.             && (length >= 2)) {
  1548.         if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor)
  1549.             != TCL_OK) {
  1550.             return TCL_ERROR;
  1551.         }
  1552.         } else if ((c == 'b')
  1553.             && (strncmp(argv[i], "-before", length) == 0)) {
  1554.         if (j == 0) {
  1555.             other = Tk_NameToWindow(interp, argv[i+1], tkwin);
  1556.             if (other == NULL) {
  1557.             return TCL_ERROR;
  1558.             }
  1559.             otherPtr = GetPacker(other);
  1560.             if (otherPtr->masterPtr == NULL) {
  1561.             goto notPacked;
  1562.             }
  1563.             masterPtr = otherPtr->masterPtr;
  1564.             prevPtr = masterPtr->slavePtr;
  1565.             if (prevPtr == otherPtr) {
  1566.             prevPtr = NULL;
  1567.             } else {
  1568.             while (prevPtr->nextPtr != otherPtr) {
  1569.                 prevPtr = prevPtr->nextPtr;
  1570.             }
  1571.             }
  1572.             positionGiven = 1;
  1573.         }
  1574.         } else if ((c == 'e')
  1575.             && (strncmp(argv[i], "-expand", length) == 0)) {
  1576.         if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) {
  1577.             return TCL_ERROR;
  1578.         }
  1579.         slavePtr->flags &= ~EXPAND;
  1580.         if (tmp) {
  1581.             slavePtr->flags |= EXPAND;
  1582.         }
  1583.         } else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) {
  1584.         if (strcmp(argv[i+1], "none") == 0) {
  1585.             slavePtr->flags &= ~(FILLX|FILLY);
  1586.         } else if (strcmp(argv[i+1], "x") == 0) {
  1587.             slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX;
  1588.         } else if (strcmp(argv[i+1], "y") == 0) {
  1589.             slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY;
  1590.         } else if (strcmp(argv[i+1], "both") == 0) {
  1591.             slavePtr->flags |= FILLX|FILLY;
  1592.         } else {
  1593.             Tcl_AppendResult(interp, "bad fill style \"", argv[i+1],
  1594.                 "\": must be none, x, y, or both", (char *) NULL);
  1595.             return TCL_ERROR;
  1596.         }
  1597.         } else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {
  1598.         if (j == 0) {
  1599.             other = Tk_NameToWindow(interp, argv[i+1], tkwin);
  1600.             if (other == NULL) {
  1601.             return TCL_ERROR;
  1602.             }
  1603.             masterPtr = GetPacker(other);
  1604.             prevPtr = masterPtr->slavePtr;
  1605.             if (prevPtr != NULL) {
  1606.             while (prevPtr->nextPtr != NULL) {
  1607.                 prevPtr = prevPtr->nextPtr;
  1608.             }
  1609.             }
  1610.             positionGiven = 1;
  1611.         }
  1612.         } else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {
  1613.         if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
  1614.             || (tmp < 0)) {
  1615.             badPad:
  1616.             Tcl_ResetResult(interp);
  1617.             Tcl_AppendResult(interp, "bad pad value \"", argv[i+1],
  1618.                 "\": must be positive screen distance",
  1619.                 (char *) NULL);
  1620.             return TCL_ERROR;
  1621.         }
  1622.         slavePtr->iPadX = tmp*2;
  1623.         } else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {
  1624.         if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
  1625.             || (tmp< 0)) {
  1626.             goto badPad;
  1627.         }
  1628.         slavePtr->iPadY = tmp*2;
  1629.         } else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {
  1630.         if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
  1631.             || (tmp< 0)) {
  1632.             goto badPad;
  1633.         }
  1634.         slavePtr->padX = tmp*2;
  1635.         } else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {
  1636.         if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
  1637.             || (tmp< 0)) {
  1638.             goto badPad;
  1639.         }
  1640.         slavePtr->padY = tmp*2;
  1641.         } else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) {
  1642.         c = argv[i+1][0];
  1643.         if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) {
  1644.             slavePtr->side = TOP;
  1645.         } else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) {
  1646.             slavePtr->side = BOTTOM;
  1647.         } else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) {
  1648.             slavePtr->side = LEFT;
  1649.         } else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) {
  1650.             slavePtr->side = RIGHT;
  1651.         } else {
  1652.             Tcl_AppendResult(interp, "bad side \"", argv[i+1],
  1653.                 "\": must be top, bottom, left, or right",
  1654.                 (char *) NULL);
  1655.             return TCL_ERROR;
  1656.         }
  1657.         } else {
  1658.         badOption:
  1659.         Tcl_AppendResult(interp, "unknown or ambiguous option \"",
  1660.             argv[i], "\": must be -after, -anchor, -before, ",
  1661.             "-expand, -fill, -in, -ipadx, -ipady, -padx, ",
  1662.             "-pady, or -side", (char *) NULL);
  1663.         return TCL_ERROR;
  1664.         }
  1665.     }
  1666.  
  1667.     /*
  1668.      * If no position in a packing list was specified and the slave
  1669.      * is already packed, then leave it in its current location in
  1670.      * its current packing list.
  1671.      */
  1672.  
  1673.     if (!positionGiven && (slavePtr->masterPtr != NULL)) {
  1674.         masterPtr = slavePtr->masterPtr;
  1675.         goto scheduleLayout;
  1676.     }
  1677.  
  1678.     /*
  1679.      * If the slave is going to be put back after itself then
  1680.      * skip the whole operation, since it won't work anyway.
  1681.      */
  1682.  
  1683.     if (prevPtr == slavePtr) {
  1684.         masterPtr = slavePtr->masterPtr;
  1685.         goto scheduleLayout;
  1686.     }
  1687.     
  1688.     /*
  1689.      * If none of the "-in", "-before", or "-after" options has
  1690.      * been specified, arrange for the slave to go at the end of
  1691.      * the order for its parent.
  1692.      */
  1693.     
  1694.     if (!positionGiven) {
  1695.         masterPtr = GetPacker(Tk_Parent(slave));
  1696.         prevPtr = masterPtr->slavePtr;
  1697.         if (prevPtr != NULL) {
  1698.         while (prevPtr->nextPtr != NULL) {
  1699.             prevPtr = prevPtr->nextPtr;
  1700.         }
  1701.         }
  1702.     }
  1703.  
  1704.     /*
  1705.      * Make sure that the slave's parent is either the master or
  1706.      * an ancestor of the master, and that the master and slave
  1707.      * aren't the same.
  1708.      */
  1709.     
  1710.     parent = Tk_Parent(slave);
  1711.     for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
  1712.         if (ancestor == parent) {
  1713.         break;
  1714.         }
  1715.         if (Tk_IsTopLevel(ancestor)) {
  1716.         Tcl_AppendResult(interp, "can't pack ", argv[j],
  1717.             " inside ", Tk_PathName(masterPtr->tkwin),
  1718.             (char *) NULL);
  1719.         return TCL_ERROR;
  1720.         }
  1721.     }
  1722.     if (slave == masterPtr->tkwin) {
  1723.         Tcl_AppendResult(interp, "can't pack ", argv[j],
  1724.             " inside itself", (char *) NULL);
  1725.         return TCL_ERROR;
  1726.     }
  1727.  
  1728.     /*
  1729.      * Unpack the slave if it's currently packed, then position it
  1730.      * after prevPtr.
  1731.      */
  1732.  
  1733.     if (slavePtr->masterPtr != NULL) {
  1734.         if ((slavePtr->masterPtr != masterPtr) &&
  1735.             (slavePtr->masterPtr->tkwin
  1736.             != Tk_Parent(slavePtr->tkwin))) {
  1737.         Tk_UnmaintainGeometry(slavePtr->tkwin,
  1738.             slavePtr->masterPtr->tkwin);
  1739.         }
  1740.         Unlink(slavePtr);
  1741.     }
  1742.     slavePtr->masterPtr = masterPtr;
  1743.     if (prevPtr == NULL) {
  1744.         slavePtr->nextPtr = masterPtr->slavePtr;
  1745.         masterPtr->slavePtr = slavePtr;
  1746.     } else {
  1747.         slavePtr->nextPtr = prevPtr->nextPtr;
  1748.         prevPtr->nextPtr = slavePtr;
  1749.     }
  1750.     Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr);
  1751.     prevPtr = slavePtr;
  1752.  
  1753.     /*
  1754.      * Arrange for the parent to be re-packed at the first
  1755.      * idle moment.
  1756.      */
  1757.  
  1758.     scheduleLayout:
  1759.     if (masterPtr->abortPtr != NULL) {
  1760.         *masterPtr->abortPtr = 1;
  1761.     }
  1762.     if (!(masterPtr->flags & REQUESTED_REPACK)) {
  1763.         masterPtr->flags |= REQUESTED_REPACK;
  1764.         Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr);
  1765.     }
  1766.     }
  1767.     return TCL_OK;
  1768. }
  1769.